#include "Camera.hpp"
#include "Config.hpp"
#include <chrono>
#include <filesystem>
#include <mutex>
#include <spdlog/spdlog.h>
#include <stdexcept>
#include <stop_token>
#include <thread>
#define STB_IMAGE_IMPLEMENTATION
#include "Config.hpp"
#include <stb/stb_image.h>

VirtualCamera::VirtualCamera(const std::string &UUID_)
    : UUID(UUID_), imgData(new unsigned char[1920 * 1080 * 3],
                           [](unsigned char *ptr) { delete[] ptr; }) {
  inf.width = 1920;
  inf.height = 1080;
  inf.type = ImageType::RGB8;
  inf.size = 1920 * 1080 * 3;
  config = new VirtualConfig(this);

  /*
  int channels;
  imgData = stbi_load(imgPath.c_str(), &inf.width, &inf.height, &channels, 0);
  switch (channels) {
  case 1:
    inf.type = ImageType::GREY;
    inf.size = inf.width * inf.height;
  case 3:
    inf.type = ImageType::RGB8;
    inf.size = inf.width * inf.height * 3;
  }
   * */
  // spdlog::info("VirtualCamera: UUID={} Path={}", UUID, imgPath.string());
  spdlog::info("Load ImageType : Width={} Height={} Channel={}", inf.width,
               inf.height, 3);
}

VirtualCamera::~VirtualCamera() { delete config; }

std::string VirtualCamera::GetUUID() { return UUID; }

bool VirtualCamera::ShotStatus() { return workThread.joinable(); }

BaseConfig *VirtualCamera::Config() {
  return dynamic_cast<BaseConfig *>(config);
}

long VirtualCamera::MaxSingleImgSize() { return inf.size; }

float VirtualCamera::FPS() { return 1; }

void VirtualCamera::StartShot() {
  if (workThread.joinable())
    return;
  workThread = std::jthread([this](std::stop_token token) {
    int frameID = 0;
    while (!token.stop_requested()) {
      {
        std::lock_guard<std::mutex> lock(imgDataMux);
        funcNewImage(frameID, (char *)(imgData.get()), "{}");
      }
      frameID++;
      std::this_thread::sleep_for(std::chrono::seconds(1));
    }
  });
}

void VirtualCamera::StopShot() {
  if (workThread.joinable()) {
    workThread.request_stop();
    workThread.join();
  }
}

BaseCamera::ImgInf VirtualCamera::ShotImageType() { return inf; }
